/*
 *  Created at 2011-12-04 19:09 GMT-03:00
 *  Author: Victor Williams Stafusa da Silva
 *  JSmartUnit
 */
package org.jsmartunit.util;

import java.util.Arrays;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.NavigableMap;
import java.util.TreeMap;

/**
 * @author Victor Williams Stafusa da Silva
 */
public class CollectionUtils {

    private CollectionUtils() {}

    public static <E> NavigableMap<Integer, E> toMap(E[] array) {
        return toMap(Arrays.asList(array));
    }

    public static <E> NavigableMap<Integer, E> toMap(Iterable<E> iterable) {
        return toMap(iterable.iterator());
    }

    public static <E> NavigableMap<Integer, E> toMap(Enumeration<E> enumeration) {
        return toMap(toIterator(enumeration));
    }

    public static <E> NavigableMap<Integer, E> toMap(Iterator<E> iterator) {
        NavigableMap<Integer, E> map = new TreeMap<Integer, E>();
        int idx = 0;
        while (iterator.hasNext()) {
            map.put(idx, iterator.next());
            idx++;
        }
        return map;
    }

    public static <E> Enumeration<E> toEnumeration(Iterator<E> iterator) {
        return new EnumerationFromIterator<E>(iterator);
    }

    public static <E> Iterator<E> toIterator(Enumeration<E> enumeration) {
        return new IteratorFromEnumeration<E>(enumeration);
    }

    private static class IteratorFromEnumeration<E> implements Iterator<E> {

        private final Enumeration<E> enumeration;

        public IteratorFromEnumeration(Enumeration<E> enumeration) {
            this.enumeration = enumeration;
        }

        @Override
        public boolean hasNext() {
            return enumeration.hasMoreElements();
        }

        @Override
        public E next() {
            return enumeration.nextElement();
        }

        @Override
        public void remove() {
            throw new UnsupportedOperationException();
        }
    }

    private static class EnumerationFromIterator<E> implements Enumeration<E> {

        private final Iterator<E> iterator;

        public EnumerationFromIterator(Iterator<E> iterator) {
            this.iterator = iterator;
        }

        @Override
        public boolean hasMoreElements() {
            return iterator.hasNext();
        }

        @Override
        public E nextElement() {
            return iterator.next();
        }
    }

    public static boolean matches(Class<?>[] classes, Object[] instances) {
        if (classes.length != instances.length) return false;
        for (int i = 0; i < instances.length; i++) {
            if (classes[i].isPrimitive()) {
                if (instances[i] == null) return false;
                if (classes[i] == int.class && instances[i].getClass() != Integer.class) return false;
                if (classes[i] == short.class && instances[i].getClass() != Short.class) return false;
                if (classes[i] == long.class && instances[i].getClass() != Long.class) return false;
                if (classes[i] == float.class && instances[i].getClass() != Float.class) return false;
                if (classes[i] == double.class && instances[i].getClass() != Double.class) return false;
                if (classes[i] == char.class && instances[i].getClass() != Character.class) return false;
                if (classes[i] == byte.class && instances[i].getClass() != Byte.class) return false;
                if (classes[i] == boolean.class && instances[i].getClass() != Boolean.class) return false;
            } else if (instances[i] != null && !classes[i].isAssignableFrom(instances[i].getClass())) {
                return false;
            }
        }
        return true;
    }

    public static void assertMatches(Class<?>[] classes, Object[] instances) {
        if (classes.length != instances.length) throw new IllegalArgumentException("Sizes do not matches.");
        for (int i = 0; i < instances.length; i++) {
            if (classes[i].isPrimitive()) {
                if (instances[i] == null) throw new IllegalArgumentException("Index " + i + " do not match.");
                if (classes[i] == int.class && instances[i].getClass() != Integer.class) throw new IllegalArgumentException("Index " + i + " do not match.");
                if (classes[i] == short.class && instances[i].getClass() != Short.class) throw new IllegalArgumentException("Index " + i + " do not match.");
                if (classes[i] == long.class && instances[i].getClass() != Long.class) throw new IllegalArgumentException("Index " + i + " do not match.");
                if (classes[i] == float.class && instances[i].getClass() != Float.class) throw new IllegalArgumentException("Index " + i + " do not match.");
                if (classes[i] == double.class && instances[i].getClass() != Double.class) throw new IllegalArgumentException("Index " + i + " do not match.");
                if (classes[i] == char.class && instances[i].getClass() != Character.class) throw new IllegalArgumentException("Index " + i + " do not match.");
                if (classes[i] == byte.class && instances[i].getClass() != Byte.class) throw new IllegalArgumentException("Index " + i + " do not match.");
                if (classes[i] == boolean.class && instances[i].getClass() != Boolean.class) throw new IllegalArgumentException("Index " + i + " do not match.");
            } else if (instances[i] != null && !classes[i].isAssignableFrom(instances[i].getClass())) {
                throw new IllegalArgumentException("Index " + i + " do not match.");
            }
        }
    }
}
